/*
 * CategoryClassificationDoubleCheck is a software package that uses 
 * data mining to verify that descriptions of items are classified 
 * into the correct categories.
 * 
 * Copyright (C) 2011  CommuniPatient, LLC
 * 
 * File: Item.java
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *  
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.unitvectory.categoryclassification;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Root;

/**
 * The information related to a single item.
 * 
 * @author Jared Hatfield
 * 
 */
@Root(name = "item")
public class Item {

    /**
     * The item identifier.
     */
    @Element(name = "id")
    protected String id;

    /**
     * The item name.
     */
    @Element(name = "name")
    protected String name;

    /**
     * The item description.
     */
    @Element(name = "description", required = false)
    protected String description;

    /**
     * The item categories.
     */
    @ElementList(name = "categories")
    protected List<Category> categories;

    /**
     * The filtered text composed of the name and description.
     */
    private String filteredText;

    /**
     * Initializes a new instance of the Item class.
     */
    public Item() {
        this.id = "";
        this.name = "";
        this.description = "";
        this.categories = new ArrayList<Category>();
        this.filteredText = null;
    }

    /**
     * Initializes a new instance of the Item class.
     * 
     * @param id
     *            The identifier.
     * @param name
     *            The name.
     * @param description
     *            The description.
     */
    public Item(String id, String name, String description) {
        this.id = id;
        this.name = name;
        this.description = description;
        this.categories = new ArrayList<Category>();
        this.filteredText = null;
    }

    /**
     * Gets the identifier.
     * 
     * @return The identifier.
     */
    public String getId() {
        return id;
    }

    /**
     * Gets the name.
     * 
     * @return The name.
     */
    public String getName() {
        return name;
    }

    /**
     * Gets the description.
     * 
     * @return The description.
     */
    public String getDescription() {
        return description;
    }

    /**
     * Gets the list of categories.
     * 
     * @return The category list.
     */
    public List<Category> getCategories() {
        return categories;
    }

    /**
     * Gets the filtered name and description for the item. The content will be
     * converted to lower case and all special and numeric characters will be
     * removed. All stop words will be removed based off of the provided list.
     * 
     * <br />
     * <br />
     * <b>Note:</b> The result of this function will be cached after the first
     * call for performance. The first list of stop words passed to the object
     * will be used and the results will be saved.
     * 
     * @param stopWords
     *            The list of stop words.
     * @return The filtered text.
     */
    public String getFilteredString(List<String> stopWords) {
        if (this.filteredText == null) {
            String body = this.getName() + this.getDescription();

            // To lower remove all non alphabetic characters and spaces
            body = body.toLowerCase();
            body = body.replaceAll("[^a-z ]", "");

            // Remove all of the stop words
            StringTokenizer st = new StringTokenizer(body);
            StringBuilder sb = new StringBuilder();
            while (st.hasMoreTokens()) {
                String token = st.nextToken();
                if (!stopWords.contains(token)) {
                    sb.append(token).append(" ");
                }
            }

            // Cache the result locally
            this.filteredText = sb.toString();
        }

        return this.filteredText;
    }

    /**
     * Tests if the item is in a specified category.
     * 
     * @param id
     *            The category id.
     * @return True item belongs to category; otherwise false.
     */
    public boolean isInCategory(String id) {
        for (int i = 0; i < this.categories.size(); i++) {
            Category cat = this.categories.get(i);
            if (cat.getId().equals(id)) {
                return true;
            }
        }

        return false;
    }
}
